package org.Yiran.timetale_re.network;

import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ItemParticleOption;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.NetworkEvent;
import org.Yiran.timetale_re.block.decorate.longtable.LongTable;
import org.Yiran.timetale_re.capability.RuneCraftingProficiencyProvider;
import org.Yiran.timetale_re.client.gui.RuneBlueprintBookViewModelScreen;
import org.Yiran.timetale_re.entity.rune.FlyingRuneEntity;
import org.Yiran.timetale_re.item.items.RuneBlueprintBookItem;
import org.Yiran.timetale_re.item.tool.screwdriver.CreativeScrewdriverItem;
import org.Yiran.timetale_re.item.tool.screwdriver.core.ScrewdriverItem;
import org.Yiran.timetale_re.item.tool.screwdriver.modules.IModule;
import org.Yiran.timetale_re.item.tool.screwdriver.modules.container.ToolModuleContainer;
import org.Yiran.timetale_re.tile.blocktile.LongTableBlockEntity;
import org.Yiran.timetale_re.util.ScrewdriverModuleUtils;
import org.Yiran.timetale_re.util.cooldown.ClientCooldownManager;

import java.util.Optional;
import java.util.function.Supplier;

/**
 * 双向网络包集合类
 * <p>
 * 包含多个用于客户端与服务端之间通信的数据包实现。
 * 每个内部类代表一种特定类型的数据包，用于处理不同的网络通信需求。
 * </p>
 */
public class SCResponsePacket {

    // ==============================
    // 飞行符文实体更新数据包
    // ==============================

    /**
     * 飞行符文实体更新数据包
     * <p>
     * 用于在客户端和服务端之间同步飞行符文实体的创建和状态更新。
     * 支持三种不同的包类型：创建新实体、更新现有实体、播放动画效果。
     * </p>
     */
    public static class RunePacket implements SimplePacket {
        // ==============================
        // 包字段
        // ==============================

        /** 包类型: 0=创建飞行符文, 1=更新飞行符文, 2=符文动画效果 */
        private final byte packetType;

        // 飞行符文相关字段
        /** 起始位置 */
        private final Vec3 startPosition; 
        /** 目标位置 */
        private final Vec3 targetPosition; 
        /** 符文物品栈 */
        private final ItemStack runeStack; 
        /** 实体ID */
        private final int entityId; 
        /** 飞行时间 */
        private final int flightTime; 
        /** 创建时间戳 */
        private final long creationTime; 

        // 动画相关字段
        /** 动画类型 */
        private final int animationType; 
        /** 粒子数量 */
        private final int particleCount; 

        // ==============================
        // 构造方法
        // ==============================

        /**
         * 构造函数 - 用于创建新飞行符文实体
         * <p>
         * 创建一个用于在客户端创建新飞行符文实体的数据包。
         * </p>
         *
         * @param startPosition 起始位置
         * @param targetPosition 目标位置
         * @param runeStack 符文物品栈
         */
        public RunePacket(Vec3 startPosition, Vec3 targetPosition, ItemStack runeStack) {
            this.packetType = 0;
            this.startPosition = startPosition;
            this.targetPosition = targetPosition;
            this.runeStack = runeStack.copy();
            this.entityId = -1;
            this.flightTime = 0;
            this.creationTime = 0;
            this.animationType = -1;
            this.particleCount = 0;
        }

        /**
         * 构造函数 - 用于更新现有飞行符文实体
         * <p>
         * 创建一个用于更新客户端现有飞行符文实体状态的数据包。
         * </p>
         *
         * @param entityId 实体ID
         * @param startPosition 起始位置
         * @param targetPosition 目标位置
         * @param flightTime 飞行时间
         * @param creationTime 创建时间戳
         */
        public RunePacket(int entityId, Vec3 startPosition, Vec3 targetPosition, int flightTime, long creationTime) {
            this.packetType = 1;
            this.entityId = entityId;
            this.startPosition = startPosition;
            this.targetPosition = targetPosition;
            this.flightTime = flightTime;
            this.creationTime = creationTime;
            this.runeStack = ItemStack.EMPTY;
            this.animationType = -1;
            this.particleCount = 0;
        }

        /**
         * 构造函数 - 用于符文动画效果
         * <p>
         * 创建一个用于播放符文动画效果的数据包。
         * </p>
         *
         * @param animationType 动画类型 (0=符文破碎, 1=飞行过程粒子)
         * @param entityId 实体ID
         * @param position 动画发生的位置
         * @param runeStack 符文物品栈
         * @param particleCount 粒子数量
         */
        public RunePacket(int animationType, int entityId, Vec3 position, ItemStack runeStack, int particleCount) {
            this.packetType = 2;
            this.animationType = animationType;
            this.entityId = entityId;
            this.startPosition = position;
            this.runeStack = runeStack;
            this.particleCount = particleCount;
            this.targetPosition = Vec3.ZERO;
            this.flightTime = 0;
            this.creationTime = 0;
        }

        /**
         * 从网络数据构造
         * <p>
         * 从网络字节缓冲区中读取数据来创建数据包实例。
         * 根据包类型读取不同的字段数据。
         * </p>
         *
         * @param buffer 网络字节缓冲区
         */
        public RunePacket(FriendlyByteBuf buffer) {
            this.packetType = buffer.readByte();

            if (this.packetType == 0) {
                // 创建新实体数据
                this.startPosition = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble());
                this.targetPosition = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble());
                this.runeStack = buffer.readItem();
                this.entityId = -1;
                this.flightTime = 0;
                this.creationTime = 0;
                this.animationType = -1;
                this.particleCount = 0;
            } else if (this.packetType == 1) {
                // 更新现有实体数据
                this.entityId = buffer.readInt();
                this.startPosition = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble());
                this.targetPosition = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble());
                this.flightTime = buffer.readInt();
                this.creationTime = buffer.readLong();
                this.runeStack = ItemStack.EMPTY;
                this.animationType = -1;
                this.particleCount = 0;
            } else {
                // 动画效果数据
                this.animationType = buffer.readInt();
                this.entityId = buffer.readInt();
                this.startPosition = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble());
                this.runeStack = buffer.readItem();
                this.particleCount = buffer.readInt();
                this.targetPosition = Vec3.ZERO;
                this.flightTime = 0;
                this.creationTime = 0;
            }
        }

        // ==============================
        // 网络通信方法
        // ==============================

        /**
         * 编码数据包
         * <p>
         * 将数据包数据写入网络字节缓冲区，用于网络传输。
         * 根据包类型写入不同的字段数据。
         * </p>
         *
         * @param buffer 网络字节缓冲区
         */
        @Override
        public void encode(FriendlyByteBuf buffer) {
            buffer.writeByte(this.packetType);

            if (this.packetType == 0) {
                // 编码创建新实体数据
                byteBuf(buffer);
                buffer.writeItem(this.runeStack);
            } else if (this.packetType == 1) {
                // 编码更新现有实体数据
                buffer.writeInt(this.entityId);
                byteBuf(buffer);
                buffer.writeInt(this.flightTime);
                buffer.writeLong(this.creationTime);
            } else {
                // 编码动画效果数据
                buffer.writeInt(this.animationType);
                buffer.writeInt(this.entityId);
                buffer.writeDouble(this.startPosition.x);
                buffer.writeDouble(this.startPosition.y);
                buffer.writeDouble(this.startPosition.z);
                buffer.writeItem(this.runeStack);
                buffer.writeInt(this.particleCount);
            }
        }

        /**
         * 辅助方法 - 将起始和目标位置写入缓冲区
         * <p>
         * 将起始位置和目标位置的坐标写入网络字节缓冲区。
         * </p>
         *
         * @param buffer 网络字节缓冲区
         */
        private void byteBuf(FriendlyByteBuf buffer) {
            buffer.writeDouble(this.startPosition.x);
            buffer.writeDouble(this.startPosition.y);
            buffer.writeDouble(this.startPosition.z);
            buffer.writeDouble(this.targetPosition.x);
            buffer.writeDouble(this.targetPosition.y);
            buffer.writeDouble(this.targetPosition.z);
        }

        /**
         * 处理数据包
         * <p>
         * 在客户端处理接收到的数据包，根据包类型执行不同的操作。
         * 包括创建新实体、更新现有实体、播放动画效果等。
         * </p>
         *
         * @param context 网络事件上下文
         */
        @Override
        public void handle(Supplier<NetworkEvent.Context> context) {
            NetworkEvent.Context ctx = context.get();
            ctx.enqueueWork(() -> {
                // 只在客户端处理数据包
                if (ctx.getDirection().getReceptionSide().isClient()) {
                    Minecraft mc = Minecraft.getInstance();
                    if (mc.level != null) {
                        switch (this.packetType) {
                            case 0: // 创建新飞行符文实体
                                FlyingRuneEntity flyingRune = new FlyingRuneEntity(
                                        mc.level,
                                        this.startPosition,
                                        this.targetPosition,
                                        this.runeStack
                                );
                                // 设置实体ID以保持同步
                                flyingRune.setId(this.entityId);
                                mc.level.addFreshEntity(flyingRune);
                                break;

                            case 1: // 更新现有飞行符文实体
                                Level level = mc.level;
                                Entity entity = level.getEntity(this.entityId);
                                if (entity instanceof FlyingRuneEntity runeEntity) {
                                    // 如果实体存在，则更新其同步数据
                                    runeEntity.setSyncData(this.startPosition, this.targetPosition, this.flightTime, this.creationTime);
                                } else {
                                    // 如果实体不存在，重新创建
                                    FlyingRuneEntity newRune = new FlyingRuneEntity(
                                            level,
                                            this.startPosition,
                                            this.targetPosition,
                                            ItemStack.EMPTY
                                    );
                                    newRune.setId(this.entityId);
                                    newRune.setSyncData(this.startPosition, this.targetPosition, this.flightTime, this.creationTime);
                                    level.addFreshEntity(newRune);
                                }
                                break;

                            case 2: // 处理动画效果
                                handleAnimation(mc);
                                break;
                        }
                    }
                }
            });
            ctx.setPacketHandled(true);
        }

        // ==============================
        // 动画处理方法
        // ==============================

        /**
         * 处理动画效果
         * <p>
         * 根据动画类型处理不同的视觉效果，包括符文破碎粒子效果和飞行过程中的附魔粒子效果。
         * </p>
         *
         * @param mc Minecraft客户端实例
         */
        private void handleAnimation(Minecraft mc) {
            switch (this.animationType) {
                case 0: // 符文破碎粒子效果
                    handleRuneBreakAnimation(mc);
                    break;

                case 1: // 飞行过程中的附魔粒子效果
                    handleFlightEnchantParticles(mc);
                    break;
            }
        }
        
        /**
         * 处理符文破碎动画
         * <p>
         * 播放玻璃破碎声音并生成基于符文物品的粒子效果
         * </p>
         *
         * @param mc Minecraft客户端实例
         */
        private void handleRuneBreakAnimation(Minecraft mc) {
            Entity entity = null;
            if (mc.level != null) {
                entity = mc.level.getEntity(entityId);
            }
            if (entity instanceof FlyingRuneEntity flyingRune) {
                // 播放玻璃破碎的声音
                playGlassBreakSound(mc, flyingRune);

                // 生成基于符文物品的粒子效果
                spawnRuneBreakParticles(mc, flyingRune);
            }
        }
        
        /**
         * 播放玻璃破碎声音
         * <p>
         * 在符文实体位置播放玻璃破碎的声音效果
         * </p>
         *
         * @param mc Minecraft客户端实例
         * @param flyingRune 飞行符文实体
         */
        private void playGlassBreakSound(Minecraft mc, FlyingRuneEntity flyingRune) {
            if (mc.level != null) {
                mc.level.playLocalSound(
                        flyingRune.getX(), flyingRune.getY(), flyingRune.getZ(),
                        SoundEvents.GLASS_BREAK, SoundSource.PLAYERS,
                        1.0F, 1.0F, false);
            }
        }
        
        /**
         * 生成符文破碎粒子
         * <p>
         * 根据符文物品生成粒子效果
         * </p>
         *
         * @param mc Minecraft客户端实例
         * @param flyingRune 飞行符文实体
         */
        private void spawnRuneBreakParticles(Minecraft mc, FlyingRuneEntity flyingRune) {
            ItemStack stack = flyingRune.getRuneStack();
            if (!stack.isEmpty()) {
                for (int i = 0; i < 8; i++) {
                    if (mc.level != null) {
                        mc.level.addParticle(
                                new ItemParticleOption(ParticleTypes.ITEM, stack),
                                flyingRune.getX(), flyingRune.getY(), flyingRune.getZ(),
                                mc.level.random.nextGaussian() * 0.1D,
                                mc.level.random.nextGaussian() * 0.1D,
                                mc.level.random.nextGaussian() * 0.1D
                        );
                    }
                }
            }
        }
        
        /**
         * 处理飞行过程中的附魔粒子
         * <p>
         * 在飞行路径上生成附魔粒子效果
         * </p>
         *
         * @param mc Minecraft客户端实例
         */
        private void handleFlightEnchantParticles(Minecraft mc) {
            for (int i = 0; i < this.particleCount; i++) {
                spawnEnchantParticle(mc);
            }
        }
        
        /**
         * 生成单个附魔粒子
         * <p>
         * 在随机位置生成一个附魔粒子
         * </p>
         *
         * @param mc Minecraft客户端实例
         */
        private void spawnEnchantParticle(Minecraft mc) {
            if (mc.level != null) {
                mc.level.addParticle(
                        ParticleTypes.ENCHANT,
                        this.startPosition.x + (mc.level.random.nextDouble() - 0.5) * 0.5D,
                        this.startPosition.y + (mc.level.random.nextDouble() - 0.5) * 0.5D,
                        this.startPosition.z + (mc.level.random.nextDouble() - 0.5) * 0.5D,
                        (mc.level.random.nextDouble() - 0.5) * 0.1D,
                        (mc.level.random.nextDouble() - 0.5) * 0.1D,
                        (mc.level.random.nextDouble() - 0.5) * 0.1D
                );
            }
        }
    }

    // ==============================
    // 冷却同步数据包
    // ==============================

    /**
     * 冷却同步数据包
     * <p>
     * 用于在服务端和客户端之间同步物品冷却状态。
     * 确保客户端能够正确显示物品的冷却时间。
     * </p>
     */
    public static class CooldownPacket implements SimplePacket {
        // ==============================
        // 包字段
        // ==============================

        /** 物品键，用于标识哪个物品正在冷却 */
        private final String itemKey;      
        /** 冷却结束时间（游戏刻） */
        private final long cooldownEnd;    

        // ==============================
        // 构造方法
        // ==============================

        /**
         * 构造冷却数据包
         * <p>
         * 创建一个用于同步物品冷却状态的数据包。
         * </p>
         *
         * @param itemKey 物品键
         * @param cooldownEnd 冷却结束时间（游戏刻）
         */
        public CooldownPacket(String itemKey, long cooldownEnd) {
            this.itemKey = itemKey;
            this.cooldownEnd = cooldownEnd;
        }

        /**
         * 从网络缓冲区读取数据
         * <p>
         * 从网络字节缓冲区中读取冷却同步数据。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        public CooldownPacket(FriendlyByteBuf buffer) {
            this.itemKey = buffer.readUtf(32767);
            this.cooldownEnd = buffer.readLong();
        }

        // ==============================
        // 网络通信方法
        // ==============================

        /**
         * 编码数据包
         * <p>
         * 将冷却同步数据写入网络字节缓冲区。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        @Override
        public void encode(FriendlyByteBuf buffer) {
            buffer.writeUtf(this.itemKey);
            buffer.writeLong(this.cooldownEnd);
        }

        /**
         * 处理数据包
         * <p>
         * 在客户端处理冷却同步数据包，更新客户端的冷却状态。
         * </p>
         *
         * @param context 网络事件上下文
         */
        @Override
        public void handle(Supplier<NetworkEvent.Context> context) {
            NetworkEvent.Context ctx = context.get();
            ctx.enqueueWork(() -> {
                // 只在客户端处理冷却同步
                if (ctx.getDirection().getReceptionSide().isClient()) {
                    Minecraft mc = Minecraft.getInstance();
                    if (mc.player != null) {
                        // 更新客户端冷却数据
                        handleCooldownSync(this.itemKey, this.cooldownEnd);
                    }
                }
            });
            ctx.setPacketHandled(true);
        }

        // ==============================
        // 冷却处理方法
        // ==============================

        /**
         * 处理冷却同步
         * <p>
         * 使用客户端冷却管理器设置冷却状态。
         * </p>
         *
         * @param itemKey 物品键
         * @param cooldownEnd 冷却结束时间（游戏刻）
         */
        private static void handleCooldownSync(String itemKey, long cooldownEnd) {
            // 使用客户端冷却管理器设置冷却状态
            ClientCooldownManager.setCooldown(itemKey, cooldownEnd);
        }
    }

    // ==============================
    // 长桌物品同步数据包
    // ==============================

    /**
     * 长桌物品同步数据包
     * <p>
     * 用于同步长桌方块实体上展示的物品状态。
     * 包括物品的设置、移除、旋转和偏移等信息。
     * </p>
     */
    public static class LongTableItemSyncPacket implements SimplePacket {
        // ==============================
        // 包字段
        // ==============================

        /** 方块位置 */
        private final BlockPos blockPos;   
        /** 部件ID (LEFT_PART or RIGHT_PART) */
        private final int partId;          
        /** 物品栈 */
        private final ItemStack itemStack; 
        /** true表示移除物品，false表示设置物品 */
        private final boolean isRemove;    
        /** 物品旋转角度 */
        private final float rotation;      
        /** 物品X轴偏移 */
        private final float xOffset;       
        /** 物品Z轴偏移 */
        private final float zOffset;       
        /** 是否包含位置信息 */
        private final boolean hasPosition; 
        /** 是否是雕刻操作 */
        private final boolean isCarving;   

        // ==============================
        // 构造方法
        // ==============================

        /**
         * 构造函数 - 用于设置物品（带位置信息）
         * <p>
         * 创建一个用于在长桌上设置物品的数据包，包含物品的位置信息。
         * </p>
         *
         * @param blockPos 方块位置
         * @param partId 部件ID
         * @param itemStack 物品栈
         * @param rotation 旋转角度
         * @param xOffset X轴偏移
         * @param zOffset Z轴偏移
         */
        public LongTableItemSyncPacket(BlockPos blockPos, int partId, ItemStack itemStack, float rotation, float xOffset, float zOffset) {
            this.blockPos = blockPos;
            this.partId = partId;
            this.itemStack = itemStack.copy();
            this.isRemove = false;
            this.rotation = rotation;
            this.xOffset = xOffset;
            this.zOffset = zOffset;
            this.hasPosition = true;
            this.isCarving = false;
        }

        /**
         * 构造函数 - 用于设置物品（不带位置信息）
         * <p>
         * 创建一个用于在长桌上设置物品的数据包，不包含物品的位置信息。
         * </p>
         *
         * @param blockPos 方块位置
         * @param partId 部件ID
         * @param itemStack 物品栈
         * @param rotation 旋转角度
         */
        public LongTableItemSyncPacket(BlockPos blockPos, int partId, ItemStack itemStack, float rotation) {
            this.blockPos = blockPos;
            this.partId = partId;
            this.itemStack = itemStack.copy();
            this.isRemove = false;
            this.rotation = rotation;
            this.xOffset = 0f;
            this.zOffset = 0f;
            this.hasPosition = false;
            this.isCarving = false;
        }

        /**
         * 构造函数 - 用于移除物品
         * <p>
         * 创建一个用于从长桌上移除物品的数据包。
         * </p>
         *
         * @param blockPos 方块位置
         * @param partId 部件ID
         */
        public LongTableItemSyncPacket(BlockPos blockPos, int partId) {
            this.blockPos = blockPos;
            this.partId = partId;
            this.itemStack = ItemStack.EMPTY;
            this.isRemove = true;
            this.rotation = 0f;
            this.xOffset = 0f;
            this.zOffset = 0f;
            this.hasPosition = false;
            this.isCarving = false;
        }

        /**
         * 构造函数 - 用于雕刻操作
         * <p>
         * 创建一个用于在长桌上进行雕刻操作的数据包。
         * </p>
         *
         * @param blockPos 方块位置
         * @param partId 部件ID
         * @param itemStack 物品栈
         * @param rotation 旋转角度
         * @param xOffset X轴偏移
         * @param zOffset Z轴偏移
         * @param isCarving 是否是雕刻操作
         */
        public LongTableItemSyncPacket(BlockPos blockPos, int partId, ItemStack itemStack, float rotation, float xOffset, float zOffset, boolean isCarving) {
            this.blockPos = blockPos;
            this.partId = partId;
            this.itemStack = itemStack.copy();
            this.isRemove = false;
            this.rotation = rotation;
            this.xOffset = xOffset;
            this.zOffset = zOffset;
            this.hasPosition = true;
            this.isCarving = isCarving;
        }

        /**
         * 从网络缓冲区读取数据
         * <p>
         * 从网络字节缓冲区中读取长桌物品同步数据。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        public LongTableItemSyncPacket(FriendlyByteBuf buffer) {
            this.blockPos = buffer.readBlockPos();
            this.partId = buffer.readInt();
            this.isRemove = buffer.readBoolean();
            this.isCarving = buffer.readBoolean(); // 读取雕刻标记
            if (!this.isRemove) {
                this.itemStack = buffer.readItem();
                this.rotation = buffer.readFloat(); // 读取旋转角度
                this.hasPosition = buffer.readBoolean(); // 读取是否有位置信息
                if (this.hasPosition) {
                    this.xOffset = buffer.readFloat(); // 读取X轴偏移
                    this.zOffset = buffer.readFloat(); // 读取Z轴偏移
                } else {
                    this.xOffset = 0f;
                    this.zOffset = 0f;
                }
            } else {
                this.itemStack = ItemStack.EMPTY;
                this.rotation = 0f;
                this.xOffset = 0f;
                this.zOffset = 0f;
                this.hasPosition = false;
            }
        }

        // ==============================
        // 网络通信方法
        // ==============================

        /**
         * 编码数据包
         * <p>
         * 将长桌物品同步数据写入网络字节缓冲区。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        @Override
        public void encode(FriendlyByteBuf buffer) {
            buffer.writeBlockPos(this.blockPos);
            buffer.writeInt(this.partId);
            buffer.writeBoolean(this.isRemove);
            buffer.writeBoolean(this.isCarving); // 写入雕刻标记
            if (!this.isRemove) {
                buffer.writeItem(this.itemStack);
                buffer.writeFloat(this.rotation); // 写入旋转角度
                buffer.writeBoolean(this.hasPosition); // 写入是否有位置信息
                if (this.hasPosition) {
                    buffer.writeFloat(this.xOffset); // 写入X轴偏移
                    buffer.writeFloat(this.zOffset); // 写入Z轴偏移
                }
            }
        }

        /**
         * 处理数据包
         * <p>
         * 在客户端处理长桌物品同步数据包，更新长桌方块实体上的物品状态。
         * </p>
         *
         * @param context 网络事件上下文
         */
        @Override
        public void handle(Supplier<NetworkEvent.Context> context) {
            NetworkEvent.Context ctx = context.get();
            ctx.enqueueWork(() -> {
                // 只在客户端处理数据包
                if (ctx.getDirection().getReceptionSide().isClient()) {
                    Minecraft mc = Minecraft.getInstance();
                    if (mc.level != null) {
                        BlockEntity blockEntity = mc.level.getBlockEntity(this.blockPos);
                        if (blockEntity instanceof LongTableBlockEntity tableEntity) {
                            // 批量更新，避免多次调用setChanged()
                            boolean changed = false;

                            if (this.isRemove) {
                                // 移除物品 - 增加双重检查
                                if (this.partId == LongTable.LEFT_PART) {
                                    // 只有当物品确实存在时才移除
                                    if (!tableEntity.leftItem.isEmpty()) {
                                        tableEntity.leftItem = ItemStack.EMPTY;
                                        tableEntity.leftItemRotation = 0f;
                                        tableEntity.leftItemXOffset = 0f;
                                        tableEntity.leftItemZOffset = 0f;
                                        changed = true;
                                    }
                                } else if (this.partId == LongTable.RIGHT_PART) {
                                    // 只有当物品确实存在时才移除
                                    if (!tableEntity.rightItem.isEmpty()) {
                                        tableEntity.rightItem = ItemStack.EMPTY;
                                        tableEntity.rightItemRotation = 0f;
                                        tableEntity.rightItemXOffset = 0f;
                                        tableEntity.rightItemZOffset = 0f;
                                        changed = true;
                                    }
                                }
                            } else {
                                // 设置物品 - 增加双重检查
                                if (this.partId == LongTable.LEFT_PART) {
                                    // 只有当物品确实不同或者位置/旋转有变化时才更新
                                    if (!ItemStack.matches(tableEntity.leftItem, this.itemStack) ||
                                            tableEntity.leftItemRotation != this.rotation ||
                                            (this.hasPosition && (tableEntity.leftItemXOffset != this.xOffset || tableEntity.leftItemZOffset != this.zOffset))) {

                                        tableEntity.leftItem = this.itemStack.copy();
                                        tableEntity.leftItemRotation = this.rotation;
                                        if (this.hasPosition) {
                                            tableEntity.leftItemXOffset = this.xOffset;
                                            tableEntity.leftItemZOffset = this.zOffset;
                                        }
                                        changed = true;
                                    }
                                } else if (this.partId == LongTable.RIGHT_PART) {
                                    // 只有当物品确实不同或者位置/旋转有变化时才更新
                                    if (!ItemStack.matches(tableEntity.rightItem, this.itemStack) ||
                                            tableEntity.rightItemRotation != this.rotation ||
                                            (this.hasPosition && (tableEntity.rightItemXOffset != this.xOffset || tableEntity.rightItemZOffset != this.zOffset))) {

                                        tableEntity.rightItem = this.itemStack.copy();
                                        tableEntity.rightItemRotation = this.rotation;
                                        if (this.hasPosition) {
                                            tableEntity.rightItemXOffset = this.xOffset;
                                            tableEntity.rightItemZOffset = this.zOffset;
                                        }
                                        changed = true;
                                    }
                                }
                            }

                            // 只有在确实发生变化时才触发更新
                            if (changed) {
                                tableEntity.setChanged();
                            }

                            // 如果是雕刻操作，播放音效
                            if (this.isCarving && mc.level != null) {
                                BlockPos soundPos = this.blockPos.relative(Direction.UP);
                                mc.level.playLocalSound(
                                        soundPos.getX() + 0.5,
                                        soundPos.getY() + 0.5,
                                        soundPos.getZ() + 0.5,
                                        SoundEvents.CHISELED_BOOKSHELF_INSERT,
                                        SoundSource.BLOCKS,
                                        1.0F,
                                        1.0F,
                                        false
                                );
                            }
                        }
                    }
                }
            });
            ctx.setPacketHandled(true);
        }
    }

    // ==============================
    // 符文蓝图书同步数据包
    // ==============================

    /**
     * 符文蓝图书同步数据包
     * <p>
     * 用于同步玩家手中的符文蓝图书的NBT数据。
     * 确保客户端和服务端的符文蓝图书数据保持一致。
     * </p>
     */
    public static class RuneBlueprintBookSyncPacket implements SimplePacket {
        // ==============================
        // 包字段
        // ==============================

        /** 蓝图书物品栈 */
        private final ItemStack bookStack; 

        // ==============================
        // 构造方法
        // ==============================

        /**
         * 构造函数
         * <p>
         * 创建一个用于同步符文蓝图书数据的数据包。
         * </p>
         *
         * @param bookStack 蓝图书物品栈
         */
        public RuneBlueprintBookSyncPacket(ItemStack bookStack) {
            this.bookStack = bookStack.copy();
        }

        /**
         * 从网络缓冲区读取数据
         * <p>
         * 从网络字节缓冲区中读取符文蓝图书同步数据。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        public RuneBlueprintBookSyncPacket(FriendlyByteBuf buffer) {
            this.bookStack = buffer.readItem();
        }

        // ==============================
        // 网络通信方法
        // ==============================

        /**
         * 编码数据包
         * <p>
         * 将符文蓝图书同步数据写入网络字节缓冲区。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        @Override
        public void encode(FriendlyByteBuf buffer) {
            buffer.writeItem(this.bookStack);
        }

        /**
         * 处理数据包
         * <p>
         * 在客户端处理符文蓝图书同步数据包，更新玩家手中的符文蓝图书数据。
         * </p>
         *
         * @param context 网络事件上下文
         */
        @Override
        public void handle(Supplier<NetworkEvent.Context> context) {
            NetworkEvent.Context ctx = context.get();
            ctx.enqueueWork(() -> {
                // 只在客户端处理数据包
                if (ctx.getDirection().getReceptionSide().isClient()) {
                    Minecraft mc = Minecraft.getInstance();
                    if (mc.player != null) {
                        // 更新玩家手中的图册
                        ItemStack mainHand = mc.player.getMainHandItem();
                        ItemStack offHand = mc.player.getOffhandItem();

                        // 检查主手或副手是否持有符文蓝图书，并更新其NBT数据
                        if (mainHand.getItem() instanceof RuneBlueprintBookItem) {
                            mainHand.setTag(bookStack.getTag());
                        } else if (offHand.getItem() instanceof RuneBlueprintBookItem) {
                            offHand.setTag(bookStack.getTag());
                        }
                    }
                }
            });
            ctx.setPacketHandled(true);
        }
    }

    // ==============================
    // 符文蓝图书视图数据包
    // ==============================

    /**
     * 符文蓝图书视图数据包
     * <p>
     * 用于在客户端打开符文蓝图书的模型查看界面。
     * </p>
     */
    public static class RuneBlueprintBookViewPacket implements SimplePacket {
        // ==============================
        // 包字段
        // ==============================

        /** 蓝图书物品栈 */
        private final ItemStack bookStack; 

        // ==============================
        // 构造方法
        // ==============================

        /**
         * 构造函数
         * <p>
         * 创建一个用于打开符文蓝图书模型查看界面的数据包。
         * </p>
         *
         * @param bookStack 蓝图书物品栈
         */
        public RuneBlueprintBookViewPacket(ItemStack bookStack) {
            this.bookStack = bookStack.copy();
        }

        /**
         * 从网络缓冲区读取数据
         * <p>
         * 从网络字节缓冲区中读取符文蓝图书视图数据。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        public RuneBlueprintBookViewPacket(FriendlyByteBuf buffer) {
            this.bookStack = buffer.readItem();
        }

        // ==============================
        // 网络通信方法
        // ==============================

        /**
         * 编码数据包
         * <p>
         * 将符文蓝图书视图数据写入网络字节缓冲区。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        @Override
        public void encode(FriendlyByteBuf buffer) {
            buffer.writeItem(this.bookStack);
        }

        /**
         * 处理数据包
         * <p>
         * 在客户端处理符文蓝图书视图数据包，打开模型查看界面。
         * </p>
         *
         * @param context 网络事件上下文
         */
        @Override
        public void handle(Supplier<NetworkEvent.Context> context) {
            NetworkEvent.Context ctx = context.get();
            ctx.enqueueWork(() -> {
                // 只在客户端处理数据包
                if (ctx.getDirection().getReceptionSide().isClient()) {
                    Minecraft mc = Minecraft.getInstance();
                    if (mc.player != null) {
                        // 打开模型查看界面
                        mc.setScreen(new RuneBlueprintBookViewModelScreen(bookStack));
                    }
                }
            });
            ctx.setPacketHandled(true);
        }
    }

    // ==============================
    // 符文制作熟练度同步数据包
    // ==============================

    /**
     * 符文制作熟练度同步数据包
     * <p>
     * 用于同步玩家的符文制作熟练度信息。
     * 确保客户端能够正确显示玩家的制符熟练度。
     * </p>
     */
    public static class RuneProficiencySyncPacket implements SimplePacket {
        // ==============================
        // 包字段
        // ==============================

        /** 熟练度等级 */
        private final int proficiencyLevel; 
        /** 经验值 */
        private final double experience;    

        // ==============================
        // 构造方法
        // ==============================

        /**
         * 构造函数 - 用于同步制符熟练度数据
         * <p>
         * 创建一个用于同步玩家制符熟练度的数据包。
         * </p>
         *
         * @param proficiencyLevel 熟练度等级
         * @param experience 经验值
         */
        public RuneProficiencySyncPacket(int proficiencyLevel, double experience) {
            this.proficiencyLevel = proficiencyLevel;
            this.experience = experience;
        }

        /**
         * 从网络缓冲区读取数据
         * <p>
         * 从网络字节缓冲区中读取符文制作熟练度同步数据。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        public RuneProficiencySyncPacket(FriendlyByteBuf buffer) {
            this.proficiencyLevel = buffer.readInt();
            this.experience = buffer.readDouble();
        }

        // ==============================
        // 网络通信方法
        // ==============================

        /**
         * 编码数据包
         * <p>
         * 将符文制作熟练度同步数据写入网络字节缓冲区。
         * </p>
         *
         * @param buffer 网络缓冲区
         */
        @Override
        public void encode(FriendlyByteBuf buffer) {
            buffer.writeInt(this.proficiencyLevel);
            buffer.writeDouble(this.experience);
        }

        /**
         * 处理数据包
         * <p>
         * 在客户端处理符文制作熟练度同步数据包，更新玩家的制符熟练度。
         * </p>
         *
         * @param context 网络事件上下文
         */
        @Override
        public void handle(Supplier<NetworkEvent.Context> context) {
            NetworkEvent.Context ctx = context.get();
            ctx.enqueueWork(() -> {
                // 只在客户端处理数据包
                if (ctx.getDirection().getReceptionSide().isClient()) {
                    Minecraft mc = Minecraft.getInstance();
                    if (mc.player != null) {
                        // 更新客户端制符熟练度数据
                        mc.player.getCapability(RuneCraftingProficiencyProvider.RUNE_CRAFTING_PROFICIENCY)
                                .ifPresent(proficiency -> {
                                    proficiency.setProficiencyLevel(this.proficiencyLevel);
                                    proficiency.setExperience(this.experience);
                                });
                    }
                }
            });
            ctx.setPacketHandled(true);
        }
    }

    /**
     * 移除指定模块数据包
     * <p>
     * 用于客户端请求移除起子中的特定模块
     * </p>
     */
    public record RemoveSpecificModulePacket(String moduleId) implements SimplePacket {

        public RemoveSpecificModulePacket(FriendlyByteBuf buffer) {
                this(buffer.readUtf(32767));
            }

            @Override
            public void encode(FriendlyByteBuf buffer) {
                buffer.writeUtf(this.moduleId);
            }

            @Override
            public void handle(Supplier<NetworkEvent.Context> context) {
                NetworkEvent.Context ctx = context.get();
                ctx.enqueueWork(() -> {
                    ServerPlayer player = ctx.getSender();
                    if (player != null) {
                        processModuleRemovalRequest(player);
                    }
                });
                ctx.setPacketHandled(true);
            }
            
            /**
             * 处理模块移除请求
             * <p>
             * 验证玩家副手物品是否为起子，并处理模块移除逻辑
             * </p>
             *
             * @param player 服务器玩家实例
             */
            private void processModuleRemovalRequest(ServerPlayer player) {
                ItemStack stack = player.getOffhandItem();
                if (stack.getItem() instanceof ScrewdriverItem screwdriverItem) {
                    // 创建模块容器并加载现有模块
                    ToolModuleContainer container = screwdriverItem.createModuleContainer(stack);
                    container.loadFromItemStack(stack);
                    
                    // 验证模块是否真的存在于起子中
                    Optional<IModule> moduleOpt = container.getModule(moduleId);
                    if (moduleOpt.isPresent()) {
                        handleValidModuleRemoval(player, stack, screwdriverItem, container);
                    } else {
                        // 显示移除失败信息 - 模块不存在于该起子中
                        player.displayClientMessage(Component.translatable("message.timetale_re.module_remove_failed",
                                Component.translatable("module." + moduleId)), true);
                    }
                }
            }
            
            /**
             * 处理有效的模块移除
             * <p>
             * 检查起子等级限制并执行模块移除操作
             * </p>
             *
             * @param player 服务器玩家实例
             * @param stack 起子物品栈
             * @param screwdriverItem 起子物品实例
             * @param container 模块容器
             */
            private void handleValidModuleRemoval(ServerPlayer player, ItemStack stack, ScrewdriverItem screwdriverItem, ToolModuleContainer container) {
                // 检查创造等级起子是否尝试移除模块
                if (screwdriverItem instanceof CreativeScrewdriverItem) {
                    player.displayClientMessage(
                        Component.translatable("message.timetale_re.creative_screwdriver_module_remove_denied"), 
                        true);
                    return;
                }
                
                // 尝试移除指定模块
                Optional<IModule> removedModuleOpt = container.removeModule(moduleId);
                if (removedModuleOpt.isPresent()) {
                    processSuccessfulModuleRemoval(player, stack, container, removedModuleOpt.get());
                } else {
                    // 显示移除失败信息
                    player.displayClientMessage(Component.translatable("message.timetale_re.module_remove_failed",
                            removedModuleOpt.get().getDisplayName()), true);
                }
            }
            
            /**
             * 处理模块移除成功的情况
             * <p>
             * 保存起子状态，将模块放到玩家物品栏或掉落在地上，并显示成功信息
             * </p>
             *
             * @param player 服务器玩家实例
             * @param stack 起子物品栈
             * @param container 模块容器
             * @param removedModule 被移除的模块
             */
            private void processSuccessfulModuleRemoval(ServerPlayer player, ItemStack stack, ToolModuleContainer container, IModule removedModule) {
                // 保存起子状态
                container.saveToItemStack(stack);

                // 将模块放到玩家物品栏或掉落在地上
                ScrewdriverModuleUtils.handleModuleRemoval(player, removedModule);

                // 显示移除成功信息
                player.displayClientMessage(Component.translatable("message.timetale_re.module_removed", removedModule.getDisplayName()), true);
            }
    }
}
